using System.Collections.Generic;
using System.IO;
using Core.Runtime;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using AssetDatabase = UnityEditor.AssetDatabase;
using Event = UnityEngine.Event;
using EventType = UnityEngine.EventType;

namespace Core.Editor
{
    /// <summary>
    /// 游戏设置面板提供器
    /// </summary>
    public class GameSettingProvider : SettingsProvider
    {
        #region Initialization
        [MenuItem("HotCore/工程配置", priority = 10000)]
        public static void OpenSettings() => SettingsService.OpenProjectSettings("HotCore/GameSettings");

        [SettingsProvider]
        private static SettingsProvider CreateSettingProvider() => new GameSettingProvider("HotCore/GameSettings", SettingsScope.Project)
        {
            keywords = GetSearchKeywordsFromGUIContentProperties<GameSettingSo>()
        };
        #endregion
        

        #region GUI Drawing
        public override void OnGUI(string searchContext)
        {
            _settings.Update();
            
            DrawSection(ref _showHybridCLRSettings, "HybridCLR Settings", DrawHybridCLRSettings);
            DrawSection(ref _showAssetSettings, "Asset Settings", DrawAssetSettings);
            DrawSection(ref _showScriptsTemplateSettings, "Scripts Template", DrawScriptsTemplateSettings);
            
            _settings.ApplyModifiedProperties();
            ForceImmediateRepaint();
        }

        private void DrawSection(ref bool showSection, string title, System.Action drawContent)
        {
            showSection = EditorGUILayout.Foldout(showSection, title, true);
            if (!showSection) return;

            EditorGUI.indentLevel++;
            EditorGUILayout.BeginVertical(GUI.skin.box);
            drawContent?.Invoke();
            EditorGUILayout.EndVertical();
            EditorGUI.indentLevel--;
        }

        private void DrawHybridCLRSettings()
        {
            EditorGUILayout.PropertyField(_settings.FindProperty("HotUpdateAssemblies"));
            EditorGUILayout.PropertyField(_settings.FindProperty("AotMetaAssemblies"));
            EditorGUILayout.PropertyField(_settings.FindProperty("LogicMainDll"));
            EditorGUILayout.PropertyField(_settings.FindProperty("AssemblyAssetExtension"));
            EditorGUILayout.PropertyField(_settings.FindProperty("AssemblyAssetPath"));

            if (GUILayout.Button("Sync HybridCLR Settings"))
            {
                SyncWithHybridCLR();
            }
        }

        private void DrawAssetSettings()
        {
            EditorGUILayout.PropertyField(_settings.FindProperty("RuntimeMode"));
            EditorGUILayout.PropertyField(_settings.FindProperty("IsEditorMode"));
            EditorGUILayout.PropertyField(_settings.FindProperty("UnloadBundleDelay"));
            EditorGUILayout.PropertyField(_settings.FindProperty("UnloadAssetDelay"));
            EditorGUILayout.PropertyField(_settings.FindProperty("MaxConcurrentTasks"));
        }
        
        private void DrawScriptsTemplateSettings()
        { 
            EditorGUILayout.PropertyField(_settings.FindProperty("UIBaseTemplate"));
            EditorGUILayout.PropertyField(_settings.FindProperty("EventBaseTemplate"));
            if (GUILayout.Button("设置默认模版"))
            {
                SetDefaultTemplate();
            }
        }
        #endregion

        #region Sync Methods
        private void SyncWithHybridCLR()
        {
            var settings = GameSettingSo.Instance;
            settings.HotUpdateAssemblies.Clear();
            settings.HotUpdateAssemblies.AddRange(HybridCLR.Editor.SettingsUtil.HotUpdateAssemblyFilesIncludePreserved);
            settings.AotMetaAssemblies.Clear();
            settings.AotMetaAssemblies.AddRange(HybridCLR.Editor.SettingsUtil.AOTAssemblyNames);
            EditorUtility.SetDirty(settings);
        }
        #endregion

        #region Lifecycle
        public override void OnActivate(string searchContext, VisualElement rootElement)
        {
            base.OnActivate(searchContext, rootElement);
            SyncWithHybridCLR();
            _settings = new SerializedObject(GameSettingSo.Instance);
            EditorApplication.update += ForceContinuousRepaint;
        }

        public override void OnDeactivate()
        {
            if (_settings != null && _settings.hasModifiedProperties)
            {
                UnityEditor.AssetDatabase.SaveAssets();
                UnityEditor.AssetDatabase.Refresh();
            }
            EditorApplication.update -= ForceContinuousRepaint;
            base.OnDeactivate();
        }
        #endregion

        #region Private Methods
        private void ForceContinuousRepaint()
        {
            var window = EditorWindow.focusedWindow;
            if (window != null && window.titleContent.text == "Project Settings")
            {
                window.Repaint();
            }
        }

        private void ForceImmediateRepaint()
        {
            if (Event.current.type == EventType.Layout)
            {
                GUI.changed = true;
                EditorWindow.focusedWindow?.Repaint();
            }
        }
        
        private void SetDefaultTemplate()
        {
            var settings = GameSettingSo.Instance;
            var ms = MonoScript.FromScriptableObject(settings);
            var path = AssetDatabase.GetAssetPath(ms);
            var resPath = Path.GetDirectoryName(path)?.Replace("Runtime\\GameSettings", "Editor\\Resources");
            var fields = settings.GetType().GetFields();
            foreach (var field in fields)
            {
                if (field.Name.EndsWith("Template"))
                {
                    var file = Path.Combine(resPath, $"{field.Name}.txt");
                    var res = AssetDatabase.LoadAssetAtPath<TextAsset>(file);
                    field.SetValue(settings, res);
                }
            }
            EditorUtility.SetDirty(settings);
        }
        #endregion

        #region Private Fields
        private SerializedObject _settings;
        private bool _showHybridCLRSettings = true;
        private bool _showAssetSettings = true;
        private bool _showScriptsTemplateSettings = true;
        #endregion

        private GameSettingProvider(string path, SettingsScope scopes, IEnumerable<string> keywords = null)
            : base(path, scopes, keywords) { }
    }
}
